package com.dupf.upms.server.controller;

import com.baidu.unbiz.fluentvalidator.ComplexResult;
import com.baidu.unbiz.fluentvalidator.FluentValidator;
import com.baidu.unbiz.fluentvalidator.ResultCollectors;
import com.dupf.common.base.BaseController;
import com.dupf.common.util.MD5Util;
import com.dupf.common.util.RedisUtil;
import com.dupf.common.validator.ChinaMobileValidator;
import com.dupf.common.validator.LengthValidator;
import com.dupf.common.validator.NotNullValidator;
import com.dupf.upms.client.shiro.session.UpmsSession;
import com.dupf.upms.client.shiro.session.UpmsSessionDao;
import com.dupf.upms.common.constant.UpmsResult;
import com.dupf.upms.common.constant.UpmsResultConstant;
import com.dupf.upms.dao.model.UpmsUser;
import com.dupf.upms.rpc.api.UpmsApiService;
import com.dupf.upms.rpc.api.UpmsSystemService;
import com.dupf.upms.rpc.api.UpmsUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONObject;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;

/**
 * 单点登录管理
 * Created by dupf on 2018/3/1.
 */
@Controller
@RequestMapping("/sso")
@Api(value = "单点登录管理", description = "单点登录管理")
public class SSOController extends BaseController {

    private static final Logger LOGGER = LoggerFactory.getLogger(SSOController.class);
    // 全局会话key
    private final static String DUPF_UPMS_SERVER_SESSION_ID = "dupf-upms-server-session-id";
    // 全局会话key列表
    private final static String DUPF_UPMS_SERVER_SESSION_IDS = "dupf-upms-server-session-ids";
    // code key
    private final static String DUPF_UPMS_SERVER_CODE = "dupf-upms-server-code";

    @Autowired
    UpmsSystemService upmsSystemService;

    @Autowired
    UpmsUserService upmsUserService;

    @Autowired
    UpmsSessionDao upmsSessionDao;

    @Autowired
    UpmsApiService upmsApiService;

    @ApiOperation(value = "登录")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public Object login(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws IOException {
        String requestStr = super.getInputStream(request);
        JSONObject data = JSONObject.fromObject(requestStr);

        String username = data.getString("username");
        String password = data.getString("password");
        String rememberMe = data.optString("rememberMe");

        if (StringUtils.isBlank(username)) {
            return new UpmsResult(UpmsResultConstant.EMPTY_USERNAME, "帐号不能为空！");
        }
        if (StringUtils.isBlank(password)) {
            return new UpmsResult(UpmsResultConstant.EMPTY_PASSWORD, "密码不能为空！");
        }
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        String sessionId = session.getId().toString();
        // 判断是否已登录，如果已登录，则回跳，防止重复登录
        String hasCode = RedisUtil.get(DUPF_UPMS_SERVER_SESSION_ID + "_" + sessionId);

        // code校验值
        // 存在退出不清除缓存导致数据一样的情况
        if (StringUtils.isBlank(hasCode)) {
            // 使用shiro认证
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
            try {
                if (BooleanUtils.toBoolean(rememberMe)) {
                    usernamePasswordToken.setRememberMe(true);
                } else {
                    usernamePasswordToken.setRememberMe(false);
                }
                subject.login(usernamePasswordToken);
            } catch (UnknownAccountException e) {
                return new UpmsResult(UpmsResultConstant.INVALID_USERNAME, "帐号不存在！");
            } catch (IncorrectCredentialsException e) {
                return new UpmsResult(UpmsResultConstant.INVALID_PASSWORD, "密码错误！");
            } catch (LockedAccountException e) {
                return new UpmsResult(UpmsResultConstant.INVALID_ACCOUNT, "帐号已锁定！");
            }
            // 更新session状态
            upmsSessionDao.updateStatus(sessionId, UpmsSession.OnlineStatus.on_line);
            // 全局会话sessionId列表，供会话管理
            RedisUtil.lpush(DUPF_UPMS_SERVER_SESSION_IDS, sessionId);
            // 默认验证帐号密码正确，创建code
            String code = UUID.randomUUID().toString();
            // 全局会话的code
            RedisUtil.set(DUPF_UPMS_SERVER_SESSION_ID + "_" + sessionId, code, (int) subject.getSession().getTimeout() / 1000);
            // code校验值
            RedisUtil.set(DUPF_UPMS_SERVER_CODE + "_" + code, code, (int) subject.getSession().getTimeout() / 1000);

            hasCode = code;
        }

        return new UpmsResult(UpmsResultConstant.SUCCESS, hasCode);
    }

    @ApiOperation(value = "校验code")
    @RequestMapping(value = "/code", method = RequestMethod.POST)
    @ResponseBody
    public Object code(HttpServletRequest request) {
        String codeParam = request.getParameter("code");
        String code = RedisUtil.get(DUPF_UPMS_SERVER_CODE + "_" + codeParam);
        if (StringUtils.isBlank(codeParam) || !codeParam.equals(code)) {
            new UpmsResult(UpmsResultConstant.FAILED, "无效code");
        }
        return new UpmsResult(UpmsResultConstant.SUCCESS, code);
    }

    @ApiOperation(value = "退出登录")
    @RequestMapping(value = "/logout", method = RequestMethod.GET)
    @ResponseBody
    public Object logout(HttpServletRequest request) {
        // shiro退出登录
        SecurityUtils.getSubject().logout();
        // 跳回原地址
//        String redirectUrl = request.getHeader("Referer");
//        if (null == redirectUrl) {
//            redirectUrl = "/";
//        }
//        return new UpmsResult(UpmsResultConstant.SUCCESS, null);

        // 跳回原地址
        String redirectUrl = request.getHeader("Referer");
        if (null == redirectUrl) {
            redirectUrl = "/";
        }
        return "redirect:" + redirectUrl;
    }

    @ApiOperation(value = "找回密码")
    @RequestMapping(value = "/user/findpwd", method = RequestMethod.POST)
    @ResponseBody
    public Object findpwd(HttpServletRequest request) throws IOException {

        JSONObject data = JSONObject.fromObject(super.getInputStream(request));

        String mobile = data.getString("mobile");
        String smsCode = data.getString("smscode");
        String newpwd = data.getString("newpassword");

        ComplexResult result = FluentValidator.checkAll()
                .on(mobile, new LengthValidator(11, 11, "手机号"))
                .on(mobile, new ChinaMobileValidator("手机号"))
                .on(newpwd, new LengthValidator(5, 32, "密码"))
                .on(smsCode, new NotNullValidator("验证码"))
                .doValidate()
                .result(ResultCollectors.toComplex());
        if (!result.isSuccess()) {
            return new UpmsResult(UpmsResultConstant.INVALID_PARAM, result.getErrors());
        }

        boolean isOK = upmsApiService.verifySmsCode(mobile, smsCode);

        if (!isOK) {
            return new UpmsResult(UpmsResultConstant.INVALID_SMSCODE, result.getErrors());
        }

        long time = System.currentTimeMillis();

        UpmsUser upmsUser = (UpmsUser) request.getAttribute("upmsUser");
        UpmsUser updateUpmsUser = new UpmsUser();
        updateUpmsUser.setUserId(upmsUser.getUserId());

        String salt = UUID.randomUUID().toString().replaceAll("-", "");
        updateUpmsUser.setSalt(salt);
        updateUpmsUser.setPassword(MD5Util.md5(upmsUser.getPassword() + upmsUser.getSalt()));
        updateUpmsUser.setUtime(time);

        upmsUserService.updateByPrimaryKey(updateUpmsUser);

        LOGGER.info("更新用户，主键：userId={}", upmsUser.getUserId());
        return new UpmsResult(UpmsResultConstant.SUCCESS, "");
    }
}
